<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>scroll实现虚拟列表</title>
    <style>
      #container {
        height: 400px;
        overflow: auto;
      }
      #wrap {
        position: relative;
      }
    </style>
  </head>
  <body>
    <div id="container">
      <div id="wrap"></div>
    </div>
    <script>
      const container = document.querySelector('#container')
      const wrap = document.querySelector('#wrap')
      const list = new Array(100000).fill('').map((_, i) => {
        return {
          title: '标题' + i
        }
      })
      const height = 50
      const count = 400 / height
      const bufferSize = 10
      wrap.style.height = height * list.length + 'px'
      let currentStartIndex = 0
      container.addEventListener('scroll', function () {
        const top = container.scrollTop
        const startIndex = Math.floor(top / height)
        if (currentStartIndex != startIndex) {
          currentStartIndex = startIndex
          rowRender()
        }
      })
      rowRender()
      function rowRender() {
        const startIndex = Math.max(currentStartIndex - bufferSize, 0)
        const endIndex = Math.min(
          currentStartIndex + count + bufferSize,
          list.length
        )
        const items = list.slice(startIndex, endIndex).map((it, i) => {
          return {
            ...it,
            height: height,
            top: (startIndex + i) * height
          }
        })
        wrap.innerHTML = items
          .map(
            it =>
              `<div style='border:1px solid red;position:absolute;top:${it.top}px;height:${it.height}px'>${it.title}</div>`
          )
          .join('')
      }
      function setPosition() {}
    </script>
  </body>
</html>
